using B.S.NewMedical.Api.Write.Application.Command.Doctor;
using B.S.NewMedical.Domain.Appointment;
using B.S.NewMedical.Domain.Hospital;
using B.S.NewMedical.ErrorCode;
using B.S.NewMedical.Infrastructure.Interface;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace B.S.NewMedical.Api.Write.Application.Handler.Doctor
{
    /// <summary>
    /// 获取待收费项目处理器
    /// </summary>
    public class GetPendingChargeItemsHandler : IRequestHandler<GetPendingChargeItemsCommand, ApiResult<PendingChargeDto>>
    {
        private readonly IBaseRepository<MedicalCard> _medicalCardRepository;
        private readonly IBaseRepository<PatientModel> _patientRepository;
        private readonly IBaseRepository<Visit> _visitRepository;
        private readonly IBaseRepository<Prescription> _prescriptionRepository;
        private readonly IBaseRepository<PrescriptionItem> _prescriptionItemRepository;
        private readonly IBaseRepository<Laborder> _laborderRepository;
        private readonly ILogger<GetPendingChargeItemsHandler> _logger;

        public GetPendingChargeItemsHandler(
            IBaseRepository<MedicalCard> medicalCardRepository,
            IBaseRepository<PatientModel> patientRepository,
            IBaseRepository<Visit> visitRepository,
            IBaseRepository<Prescription> prescriptionRepository,
            IBaseRepository<PrescriptionItem> prescriptionItemRepository,
            IBaseRepository<Laborder> laborderRepository,
            ILogger<GetPendingChargeItemsHandler> logger)
        {
            _medicalCardRepository = medicalCardRepository;
            _patientRepository = patientRepository;
            _visitRepository = visitRepository;
            _prescriptionRepository = prescriptionRepository;
            _prescriptionItemRepository = prescriptionItemRepository;
            _laborderRepository = laborderRepository;
            _logger = logger;
        }

        public async Task<ApiResult<PendingChargeDto>> Handle(GetPendingChargeItemsCommand request, CancellationToken cancellationToken)
        {
            try
            {
                _logger.LogInformation("开始获取待收费项目，就诊卡号: {CardNo}", request.CardNo);

                // 参数验证
                if (string.IsNullOrWhiteSpace(request.CardNo))
                    return new ApiResult<PendingChargeDto> { Code = ApiEnum.Fail, Msg = "就诊卡号不能为空" };

                // 根据就诊卡号查找患者
                var medicalCard = await _medicalCardRepository.GetAll()
                    .FirstOrDefaultAsync(mc => mc.Card_no == request.CardNo && !mc.IsDeleted, cancellationToken);

                if (medicalCard == null)
                    return new ApiResult<PendingChargeDto> { Code = ApiEnum.Fail, Msg = "就诊卡不存在" };

                var patient = await _patientRepository.GetAll()
                    .FirstOrDefaultAsync(p => p.Id == medicalCard.Patient_id && !p.IsDeleted, cancellationToken);

                if (patient == null)
                    return new ApiResult<PendingChargeDto> { Code = ApiEnum.Fail, Msg = "患者信息不存在" };

                // 获取该患者所有的就诊记录
                var visits = await _visitRepository.GetAll()
                    .Where(v => v.Patient_id == patient.Id && !v.IsDeleted)
                    .ToListAsync(cancellationToken);

                var visitIds = visits.Select(v => v.Id).ToList();

                // 获取待收费的处方
                var pendingPrescriptions = await _prescriptionRepository.GetAll()
                    .Where(p => visitIds.Contains(p.visit_id) && p.status == "待收费" && !p.IsDeleted)
                    .ToListAsync(cancellationToken);

                // 获取待收费的检验单
                var pendingLaborders = await _laborderRepository.GetAll()
                    .Where(l => visitIds.Contains(l.Visit_id) && l.Status == "待收费" && !l.IsDeleted)
                    .ToListAsync(cancellationToken);

                // 组装处方信息
                var prescriptionDtos = new List<PendingPrescriptionDto>();
                foreach (var prescription in pendingPrescriptions)
                {
                    var prescriptionItems = await _prescriptionItemRepository.GetAll()
                        .Where(pi => pi.Prescription_id == prescription.Id && !pi.IsDeleted)
                        .ToListAsync(cancellationToken);

                    var itemDtos = prescriptionItems.Select(item => new PrescriptionItemDto
                    {
                        DrugCode = item.Drug_code,
                        DrugName = item.Drug_name,
                        Spec = item.Spec,
                        Qty = item.Qty,
                        Unit = item.Unit,
                        Days = item.Days,
                        Price = item.Price,
                        Amount = item.Amount
                    }).ToList();

                    prescriptionDtos.Add(new PendingPrescriptionDto
                    {
                        PrescriptionId = prescription.Id,
                        PrescriptionNo = prescription.prescription_no,
                        Type = prescription.type,
                        CreateTime = prescription.create_time,
                        Amount = itemDtos.Sum(i => i.Amount),
                        Items = itemDtos
                    });
                }

                // 组装检验单信息
                var laborderDtos = pendingLaborders.Select(lab => new PendingLaborderDto
                {
                    LaborderId = lab.Id,
                    OrderNo = lab.Order_no,
                    ItemName = lab.Item_name,
                    CreateTime = lab.Create_time,
                    Price = lab.Price
                }).ToList();

                // 计算总金额
                var totalAmount = prescriptionDtos.Sum(p => p.Amount) + laborderDtos.Sum(l => l.Price);

                var result = new PendingChargeDto
                {
                    Patient = new PatientInfoDto
                    {
                        PatientId = patient.Id,
                        PatientName = patient.Name,
                        CardNo = request.CardNo,
                        CardBalance = medicalCard.Card_price,
                        CardStatus = medicalCard.Status
                    },
                    Prescriptions = prescriptionDtos,
                    Laborders = laborderDtos,
                    TotalAmount = totalAmount
                };

                _logger.LogInformation("成功获取待收费项目，处方数: {PrescriptionCount}，检验单数: {LaborderCount}，总金额: {TotalAmount}",
                    prescriptionDtos.Count, laborderDtos.Count, totalAmount);

                return new ApiResult<PendingChargeDto>
                {
                    Code = ApiEnum.Success,
                    Msg = "获取成功",
                    Data = result
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取待收费项目时发生错误，就诊卡号: {CardNo}", request.CardNo);
                return new ApiResult<PendingChargeDto>
                {
                    Code = ApiEnum.Fail,
                    Msg = "获取待收费项目失败"
                };
            }
        }
    }
} 